package com.hq.xmind;

/**
 * @ClassName ValidateHTML
 * @Description TODO
 * @Author huangzl
 * @Date 2018/11/16 14:26
 * @Version 1.0
 * 用于校验HTML标签是否合法，是否闭合
 **/

import org.apache.commons.lang.StringUtils;
import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.nodes.RemarkNode;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.NodeIterator;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;


public class ValidateHTML {

    private final String CONTENT;
    private Parser parser;
    private StringBuilder stringBuilder = new StringBuilder();

    public ValidateHTML(String content) {
        CONTENT = content;
        parser = Parser.createParser(content, "GBK");
    }

    private static String getContent() {
        byte[] con = null;
        InputStream in = ValidateHTML.class.getResourceAsStream("content.txt");
        try {
            int length = in.available();
            con = new byte[length];
            in.read(con, 0, length);
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            return new String(con, "GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return "";
        }
    }

    private void recusive(NodeIterator iterator) throws Exception {
        while (iterator.hasMoreNodes()) {
            Node node = iterator.nextNode();

            if (node instanceof TagNode) {
                TagNode tagNode = (TagNode) node;

                if (!isClosed(tagNode)) {
                    throw new Exception("发现不完整的错误标签");
                }

                if (moreTag(tagNode)) {
                    throw new Exception("发现多余的结束标签");
                }

                TagNode endTagNode = (TagNode) tagNode.getEndTag();
                if (endTagNode == null) {
                    continue;
                }

                if (isIgnored(endTagNode)) {
                    throw new Exception("发现没有闭合的标签");
                }
            } else if (node instanceof RemarkNode) {
                RemarkNode remarkNode = (RemarkNode) node;
                if (!remarkNode.toHtml().endsWith("-->")) {
                    throw new Exception("发现没有闭合的注释标签");
                }
            }

            if (node.getChildren() == null) {
                continue;
            }
            recusive(node.getChildren().elements());
        }
    }

    private boolean isIgnored(TagNode tagNode) {
        String tagName = tagNode.getTagName();
        int position = tagNode.getTagBegin();
        int length = tagName.length() + 3;
        String subString = StringUtils.substring(CONTENT, position, position + length);
        if (subString == null) {
            return true;
        }

        return !subString.equalsIgnoreCase("</" + tagName + ">");
    }


    private boolean moreTag(TagNode tagNode) {
        return tagNode.toHtml().startsWith("</");
    }


    //检测不完整的标签或错误标签，例如<script </script>
    private boolean isClosed(TagNode tagNode) {
        System.out.println(tagNode.toHtml());
        System.out.println("=================================");

        String html = tagNode.toHtml();
        stringBuilder.append(html);
        int length = tagNode.getTagEnd() - tagNode.getTagBegin();
        String tag = StringUtils.substring(html, 0, length);
        return tag.endsWith(">");
    }


    public boolean validate() {
        try {
            recusive(parser.elements());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) {
        String c = "\n" +
                "<div itemprop=\"knowledge\">\n" +
                "\n" +
                "# Python\n" +

                "\n" +
                "## 什么是python ?\n" +
                "![](http://hqjy-course.oss-cn-shenzhen.aliyuncs.com/18-10-25/85796217.jpg)\n" +
                "\n" +
                "Python是一种计算机程序设计语言。是一种动态的、面向对象的脚本语言，最初被设计用于编写自动化脚本(shell)，随着版本的不断更新和语言新功能的添加，越来越多被用于独立的、大型项目的开发。\n" +
                "</div>\n" +
                "<div itemprop=\"where\">\n" +
                "\n" +
                "## Python可以用在哪些领域 ?\n" +
                "* 系统编程\n" +
                "* 图像处理\n" +
                "* 人工智能\n" +
                "* web编程\n" +
                "</div>\n" +
                "\n" +
                "<div itemprop=\"how\">\n" +
                "\n" +
                "## 如何编写一个Python程序\n" +
                "```python\n" +
                "print(\"Hello,world!\")\n" +
                "```\n" +
                "</div>\n" +
                "\n" +
                "</div>\n" +
                "\n" +
                "<div itemprop=\"knowledge\">\n" +
                "\n" +
                "# JAVA学科,Javaweb基础,前端基础,HTML\n" +
                "\n" +
                "<div itemprop=\"what\">\n" +
                "\n" +
                "## 什么是HTML ?\n" +
                "超文本标记语言，标准通用标记语言下的一个应用。\n" +
                "“超文本”就是指页面内可以包含图片、链接，甚至音乐、程序等非文字元素。\n" +
                "超文本标记语言的结构包括“头”部分（英语：Head）、和“主体”部分（英语：Body），其中“头”部提供关于网页的信息，“主体”部分提供网页的具体内容。\n" +
                "</div>\n" +
                "\n" +
                "\n" +
                "<div itemprop=\"where\">\n" +
                "\n" +
                "## HTML使用领域\n" +
                "* 网页\n" +
                "* 桌面程序界面\n" +
                "</div>\n" +
                "</div>";
        ValidateHTML app = new ValidateHTML(c);
        boolean result = app.validate();
        if(!result){
            System.out.println(result);
//            System.out.println(app.stringBuilder);
        }

    }
}